package ai.plantdata.dao.strategy.impl;

import ai.plantdata.dao.dto.AssociateDTO;
import ai.plantdata.dao.dto.EntityAssociateConceptTable;
import ai.plantdata.dao.strategy.SeparateHandle;
import ai.plantdata.dao.util.JdbcUtils;
import ai.plantdata.graph.api.Node;
import ai.plantdata.graph.api.Property;
import ai.plantdata.graph.api.schema.ConceptDefinition;
import ai.plantdata.graph.api.schema.NumericDefinition;
import ai.plantdata.graph.mongo.MongoGraphStore;
import ai.plantdata.vo.DataSourceConfig;
import ai.plantdata.dao.util.BeanTransform;
import ai.plantdata.vo.SeparateTable;
import org.springframework.util.CollectionUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Author: WangHui
 * @Date: 2021/7/19 10:37
 * @Description:
 */
public class EntityAssociateConcept implements SeparateHandle {
    @Override
    public List<ConceptDefinition> schemaHandle(SeparateTable separateDTO, DataSourceConfig dataSourceConfig, MongoGraphStore store) {
        EntityAssociateConceptTable entityTable = BeanTransform.separateTableToEntityAssociateConceptTable(separateDTO);
        Connection conn = JdbcUtils.getConnection(dataSourceConfig);
        String tableName = entityTable.getTableName();
        List<String> fieldNames = entityTable.getFieldName();
        List<NumericDefinition> numDef = getNumDef(conn, tableName, fieldNames);

        List<ConceptDefinition> conceptDefinitions = new ArrayList<>();
        AssociateDTO associateDTO = entityTable.getAssociateDTO();
        String assoTableName = associateDTO.getTableName();
        String assoNameField = associateDTO.getNameField();
        String assoMeanTagField = associateDTO.getMeanTagField();
        List<Map<String, String>> token = getToken(conn, assoTableName, assoNameField, assoMeanTagField);
        if (!CollectionUtils.isEmpty(token)) {
            for (Map<String, String> map : token) {
                ConceptDefinition conceptDefinition = ConceptDefinition.create(map.get("name"), map.get("meanTag"));
                conceptDefinition.setAttributes(numDef);
                store.saveSchema(conceptDefinition);
                conceptDefinitions.add(conceptDefinition);
            }
        }
        if (!CollectionUtils.isEmpty(conceptDefinitions)) {
            store.saveSchema(conceptDefinitions);
        }
        return conceptDefinitions;
    }

    @Override
    public void entityHandle(SeparateTable separateDTO, DataSourceConfig dataSourceConfig, MongoGraphStore store) {
        EntityAssociateConceptTable table = BeanTransform.separateTableToEntityAssociateConceptTable(separateDTO);
        List<String> fieldName = table.getFieldName();
        String meanTagField = table.getMeanTagField();
        String tableName = table.getTableName();
        String nameField = table.getNameField();
        AssociateDTO associateDTO = table.getAssociateDTO();
        String associationField = table.getAssociationField();
        Connection conn = JdbcUtils.getConnection(dataSourceConfig);
        try {
            if (CollectionUtils.isEmpty(fieldName)) {
                fieldName = new ArrayList<>();
            }
            StringBuilder str = new StringBuilder();
            for (String s : fieldName) {
                str.append(" , ").append(s);
            }
            List<Node> nodes = new ArrayList<>();
            String sql;
            if (meanTagField == null) {
                sql = "select %s , %s %s from %s";
                sql = String.format(sql, nameField, associationField, str, tableName);
                PreparedStatement ps = conn.prepareStatement(sql);
                ResultSet rs = ps.executeQuery();
                while (rs.next()) {
                    Object object = rs.getObject(2);
                    Map<String, String> map = getAssociate(conn, associateDTO, object);
                    if (map == null) {
                        throw new RuntimeException("父概念不存在");
                    }
                    Node node = Node.create(rs.getObject(1, String.class)).label(map.get("name"), map.get("meanTag"));
                    List<Property> properties = new ArrayList<>();
                    for (int i = 0; i < fieldName.size(); i++) {
                        Property property = Property.create(fieldName.get(i), rs.getObject(3 + i));
                        properties.add(property);
                    }
                    node.setProperties(properties);
                    nodes.add(node);
                    if (nodes.size() % 10_000 == 0) {
                        //保存关系
                        store.saveNodeWithProperty(node);
                        nodes.clear();
                    }
                }
                JdbcUtils.close(ps, rs);
            } else {
                sql = "select %s , %s , %s %s from %s";
                sql = String.format(sql, nameField, meanTagField, associationField, str, tableName);
                PreparedStatement ps = conn.prepareStatement(sql);
                ResultSet rs = ps.executeQuery();
                while (rs.next()) {
                    Object object = rs.getObject(3);
                    Map<String, String> map = getAssociate(conn, associateDTO, object);
                    if (map == null) {
                        throw new RuntimeException("父概念不存在");
                    }
                    Node node = Node.create(rs.getObject(1, String.class), rs.getObject(2, String.class)).label(map.get("name"), map.get("meanTag"));
                    List<Property> properties = new ArrayList<>();
                    for (int i = 0; i < fieldName.size(); i++) {
                        Property property = Property.create(fieldName.get(i), rs.getObject(4 + i));
                        properties.add(property);
                    }
                    node.setProperties(properties);
                    nodes.add(node);
                    if (nodes.size() % 10_000 == 0) {
                        //保存关系
                        store.saveNodeWithProperty(node);
                        nodes.clear();
                    }
                }
                JdbcUtils.close(ps, rs);
                if (!nodes.isEmpty()) {
                    store.saveNodeWithProperty(nodes);
                    nodes.clear();
                }
            }
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
